package com.ljc.listener;

import com.google.gson.Gson;
import com.ljc.constant.RabbitMqConstant;
import com.ljc.constant.RedisConstant;
import com.ljc.model.entity.InterfaceInfo;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;

@Component
@Slf4j
public class InterfaceListener {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 异步删除缓存队列
     */
    @RabbitListener(queues = RabbitMqConstant.INTERFACE_DELETE_QUEUE_NAME)
    public void interfaceDeleteListener(String interfaceInfoJson, Message message, Channel channel) throws IOException {
        String messageId = message.getMessageProperties().getMessageId();
        String retry = stringRedisTemplate.opsForValue().get(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
        if (StringUtils.isEmpty(retry)) {
            log.warn("接口操作已经处理过：{}", messageId);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        int retryCount = Integer.parseInt(retry);
        // 判断是否重试3次，如果重试三次就不再投递，而是进行警告措施
        if (retryCount > 3) {
            //重试次数大于3，直接放到死信队列
            log.error("接口操作重试超过3次：{}", messageId);
            //basicReject方法拒绝deliveryTag对应的消息，第二个参数是否requeue，true则重新入队列，否则丢弃或者进入死信队列。
            //该方法reject后，该消费者还是会消费到该条被reject的消息。
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            stringRedisTemplate.delete(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            return;
        }
        try {
            InterfaceInfo interfaceInfo = new Gson().fromJson(interfaceInfoJson, InterfaceInfo.class);
            Long interfaceInfoId = interfaceInfo.getId();
            stringRedisTemplate.delete(RedisConstant.INTERFACE_INFO_PREFIX + interfaceInfoId);
            stringRedisTemplate.delete(RedisConstant.INTERFACE_INVOKE_METHOD_PREFIX + interfaceInfo.getMethod());
            stringRedisTemplate.delete(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            stringRedisTemplate.opsForValue().increment(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            throw new RuntimeException(e);
        }
    }

    /**
     * 异步更新缓存队列
     */
    @RabbitListener(queues = RabbitMqConstant.INTERFACE_UPDATE_QUEUE_NAME)
    public void interfaceUpdateListener(String interfaceInfoJson, Message message, Channel channel) throws IOException {
        String messageId = message.getMessageProperties().getMessageId();
        String retry = stringRedisTemplate.opsForValue().get(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
        if (StringUtils.isEmpty(retry)) {
            log.warn("接口操作已经处理过：{}", messageId);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        int retryCount = Integer.parseInt(retry);
        // 判断是否重试3次，如果重试三次就不再投递，而是进行警告措施
        if (retryCount > 3) {
            //重试次数大于3，直接放到死信队列
            log.error("接口操作重试超过3次：{}", messageId);
            //basicReject方法拒绝deliveryTag对应的消息，第二个参数是否requeue，true则重新入队列，否则丢弃或者进入死信队列。
            //该方法reject后，该消费者还是会消费到该条被reject的消息。
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            stringRedisTemplate.delete(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            return;
        }
        try {
            InterfaceInfo interfaceInfo = new Gson().fromJson(interfaceInfoJson, InterfaceInfo.class);
            Long interfaceInfoId = interfaceInfo.getId();
            stringRedisTemplate.opsForValue().set(RedisConstant.INTERFACE_INFO_PREFIX + interfaceInfoId, new Gson().toJson(interfaceInfo));
            HashMap<String, String> map = new HashMap<>();
            map.put(interfaceInfo.getUrl(), String.valueOf(interfaceInfoId));
            stringRedisTemplate.opsForHash().putAll(RedisConstant.INTERFACE_INVOKE_METHOD_PREFIX + interfaceInfo.getMethod(), map);
            stringRedisTemplate.delete(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            stringRedisTemplate.opsForValue().increment(RedisConstant.INTERFACE_RETRY_PREFIX + messageId);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断是否重试3次，如果重试三次就不再投递，而是进行警告措施
     */
    @RabbitListener(queues = RabbitMqConstant.INTERFACE_ERROR_QUEUE_NAME)
    public void interfaceErrorListener(Message message, Channel channel) {
        String messageId = message.getMessageProperties().getMessageId();
        try {
            log.error("接口缓存操重试3次后依然出错!MessageId：{}", messageId);
            // TODO 进行警告措施【发送邮件】
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // TODO 进行警告措施【发送邮件】
            log.error("死信队列出错！MessageId：{}", messageId);
            throw new RuntimeException(e);
        }
    }
}
